home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / c / tde31.zip / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-08-29  |  39KB  |  1,249 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - window module
  10.  * Purpose: This file contains the code associated with opening and sizing
  11.  *           windows, and also displaying the help window.
  12.  * File:    window.c
  13.  * Author:  Douglas Thomson
  14.  * System:  this file is intended to be system-independent
  15.  * Date:    October 12, 1989
  16.  */
  17. /*********************  end of original comments   ********************/
  18.  
  19.  
  20. /*
  21.  * The window routines have been EXTENSIVELY rewritten.  Some routines were
  22.  * changed so only one logical function is carried out, eg. 'initialize_window'.
  23.  * I like the Microsoft way of resizing windows - just press the up and down
  24.  * arrows to adjust the window to desired size.  I also like pressing one key
  25.  * to change windows.  All of which are implemented in TDE.
  26.  *
  27.  * In TDE, version 1.4, I added support for vertical windows.
  28.  *
  29.  * New editor name:  TDE, the Thomson-Davis Editor.
  30.  * Author:           Frank Davis
  31.  * Date:             June 5, 1991, version 1.0
  32.  * Date:             July 29, 1991, version 1.1
  33.  * Date:             October 5, 1991, version 1.2
  34.  * Date:             January 20, 1992, version 1.3
  35.  * Date:             February 17, 1992, version 1.4
  36.  * Date:             April 1, 1992, version 1.5
  37.  * Date:             June 5, 1992, version 2.0
  38.  * Date:             October 31, 1992, version 2.1
  39.  * Date:             April 1, 1993, version 2.2
  40.  * Date:             June 5, 1993, version 3.0
  41.  * Date:             August 29, 1993, version 3.1
  42.  *
  43.  * This modification of Douglas Thomson's code is released into the
  44.  * public domain, Frank Davis.  You may distribute it freely.
  45.  */
  46.  
  47. #include "tdestr.h"
  48. #include "common.h"
  49. #include "define.h"
  50. #include "tdefunc.h"
  51.  
  52.  
  53. /*
  54.  * Name:    initialize_window
  55.  * Purpose: To open a new window
  56.  * Date:    June 5, 1991
  57.  * Returns: OK if window opened successfully
  58.  *          ERROR if anything went wrong
  59.  * Notes:   If this is first window, then set up as normal displayed window;
  60.  *          otherwise, make the present window invisible and open a new
  61.  *          window in the same screen location as the old one.
  62.  */
  63. int  initialize_window( void )
  64. {
  65. int  top;
  66. int  bottom;
  67. int  start_col;
  68. int  end_col;
  69. WINDOW *wp;        /* used for scanning windows */
  70. WINDOW *window;
  71. register file_infos *fp;     /* used for scanning files */
  72. register int rc;
  73. line_list_ptr ll;
  74. line_list_ptr temp_ll;
  75.  
  76.    rc = OK;
  77.    window = g_status.current_window;
  78.    fp = g_status.current_file;
  79.    if (window == NULL) {
  80.       /*
  81.        * special case if this is the first window on screen.
  82.        */
  83.       top = start_col = 0;
  84.       bottom  = g_display.nlines;
  85.       end_col = g_display.ncols - 1;
  86.    } else {
  87.       /*
  88.        * else put the new window in same place as current window.
  89.        *  make current window invisible.  new window becomes current window.
  90.        */
  91.       top       = window->top_line - 1;
  92.       bottom    = window->bottom_line;
  93.       start_col = window->start_col;
  94.       end_col   = window->end_col;
  95.    }
  96.  
  97.    assert( top < bottom );
  98.    assert( start_col < end_col );
  99.    assert( fp != NULL );
  100.  
  101.    if (create_window( &wp, top, bottom, start_col, end_col, fp ) == ERROR) {
  102.       /*
  103.        * out of memory
  104.        */
  105.       error( WARNING, bottom, main4 );
  106.  
  107.       /*
  108.        * This is a real nuisance. We had room for the file and the
  109.        *  file structure, but not enough for the window as well.
  110.        * Now we must free all the memory that has already been
  111.        *  allocated.
  112.        */
  113.       if (fp->ref_count == 0) {
  114.  
  115.          /*
  116.           * remove fp from file pointer list.
  117.           */
  118.          if (fp->prev != NULL)
  119.             fp->prev->next = fp->next;
  120.          else
  121.             g_status.file_list = fp->next;
  122.  
  123.          if (fp->next != NULL)
  124.             fp->next->prev = fp->prev;
  125.  
  126.          /*
  127.           * free the undo stack, line pointers, and linked list.
  128.           */
  129.  
  130.          ll = fp->undo_top;
  131.          while (ll != NULL) {
  132.             temp_ll = ll->next;
  133.             if (ll->line != NULL)
  134.                my_free( ll->line );
  135.             my_free( ll );
  136.             ll = temp_ll;
  137.          }
  138.  
  139.          ll = fp->line_list;
  140.          while (ll != NULL) {
  141.             temp_ll = ll->next;
  142.             if (ll->line != NULL)
  143.                my_free( ll->line );
  144.             my_free( ll );
  145.             ll = temp_ll;
  146.          }
  147.  
  148. #if defined( __MSC__ )
  149.          _fheapmin( );
  150. #endif
  151.  
  152.          free( fp );
  153.          wp = g_status.current_window;
  154.          if (wp != NULL && wp->visible)
  155.             g_status.current_file = wp->file_info;
  156.          else
  157.             g_status.stop = TRUE;
  158.       }
  159.       rc = ERROR;
  160.    }
  161.  
  162.    if (rc != ERROR) {
  163.       /*
  164.        * set up the new cursor position as appropriate
  165.        */
  166.       wp->ccol = wp->start_col;
  167.       wp->rcol = wp->bcol = 0;
  168.       wp->rline = 1L;
  169.       wp->ll    = fp->line_list;
  170.       wp->visible = TRUE;
  171.       wp->letter = fp->next_letter++;
  172.       if (window != NULL)
  173.          window->visible = FALSE;
  174.  
  175.       /*
  176.        * the new window becomes the current window.
  177.        */
  178.       g_status.current_window = wp;
  179.    }
  180.    return( rc );
  181. }
  182.  
  183.  
  184. /*
  185.  * Name:    next_window
  186.  * Purpose: To move to the next visible window.
  187.  * Date:    June 5, 1991
  188.  * Passed:  window:  pointer to current window
  189.  * Notes:   Start with current window.  If next window exists then go to it
  190.  *           else go to the first (top) window on screen.
  191.  *          When I added vertical windows, finding the "correct" next
  192.  *           window became extremely, unnecessarily, unmanageably complicated.
  193.  *           let's just use a simple procedure to find the first available,
  194.  *           visible, next window.
  195.  */
  196. int  next_window( WINDOW *window )
  197. {
  198. register WINDOW *wp;
  199. int  change;
  200.  
  201.    if (window != NULL) {
  202.       change = FALSE;
  203.       /*
  204.        * start with current window and look for first next
  205.        *  visible window
  206.        */
  207.       wp = window->next;
  208.       while (wp != NULL) {
  209.          if (wp->visible) {
  210.             change = TRUE;
  211.             break;
  212.          }
  213.          wp = wp->next;
  214.       }
  215.  
  216.       /*
  217.        * if we haven't found a visible window yet, go to the beginning of
  218.        *  the list until we find a visible window.
  219.        */
  220.       if (!change) {
  221.          wp = g_status.window_list;
  222.          while (wp != window) {
  223.             if (wp->visible) {
  224.                change = TRUE;
  225.                break;
  226.             }
  227.             wp = wp->next;
  228.          }
  229.       }
  230.       if (change == TRUE) {
  231.          entab_linebuff( );
  232.          un_copy_line( window->ll, window, TRUE );
  233.          g_status.current_window = wp;
  234.          g_status.current_file = wp->file_info;
  235.       }
  236.    }
  237.    return( OK );
  238. }
  239.  
  240.  
  241. /*
  242.  * Name:    prev_window
  243.  * Purpose: To move to the previous visible window.
  244.  * Date:    June 5, 1991
  245.  * Passed:  window:  pointer to current window
  246.  * Notes:   Start with current window.  If previous window exists then go to
  247.  *           it else go to the last (bottom) window on screen.  Opposite of
  248.  *           next_window.
  249.  *          when I added vertical windows, finding the "correct" previous
  250.  *           window became extremely, unnecessarily, unmanageably complicated.
  251.  *           let's just use a simple procedure to find the first available,
  252.  *           visible, previous window.
  253.  */
  254. int  prev_window( WINDOW *window )
  255. {
  256. register WINDOW *wp;
  257. int  change;
  258.  
  259.    if (window != NULL) {
  260.       change = FALSE;
  261.  
  262.       /*
  263.        * start with current window and look for first previous
  264.        *  visible window
  265.        */
  266.       wp = window->prev;
  267.       while (wp != NULL) {
  268.          if (wp->visible) {
  269.             change = TRUE;
  270.             break;
  271.          }
  272.          wp = wp->prev;
  273.       }
  274.  
  275.       /*
  276.        * if we haven't found a visible window yet, go to the end of
  277.        *  the list and work backwards until we find a visible window.
  278.        */
  279.       if (!change) {
  280.          wp = window->next;
  281.          if (wp != NULL) {
  282.             while (wp->next != NULL)
  283.                wp = wp->next;
  284.             while (wp != window) {
  285.                if (wp->visible) {
  286.                   change = TRUE;
  287.                   break;
  288.                }
  289.                wp = wp->prev;
  290.             }
  291.          }
  292.       }
  293.       if (change == TRUE) {
  294.          entab_linebuff( );
  295.          un_copy_line( window->ll, window, TRUE );
  296.          g_status.current_window = wp;
  297.          g_status.current_file = wp->file_info;
  298.       }
  299.    }
  300.    return( OK );
  301. }
  302.  
  303.  
  304. /*
  305.  * Name:    split_horizontal
  306.  * Purpose: To split screen horizontally at the cursor.
  307.  * Date:    June 5, 1991
  308.  * Passed:  window:  pointer to current window
  309.  * Notes:   split the screen horizontally at the cursor position.
  310.  */
  311. int  split_horizontal( WINDOW *window )
  312. {
  313. register WINDOW *wp;
  314. register WINDOW *win;   /* register pointer for window */
  315. WINDOW *temp;
  316. file_infos *file;       /* file structure for file belonging to new window */
  317. int  rc;
  318.  
  319.    rc = OK;
  320.    win = window;
  321.    if ( win != NULL) {
  322.  
  323.       /*
  324.        * check that there is room for the window
  325.        */
  326.       if (win->bottom_line - win->cline < 2) {
  327.          /*
  328.           * move cursor up first
  329.           */
  330.          error( WARNING, win->bottom_line, win1 );
  331.          rc = ERROR;
  332.       } else {
  333.          file = win->file_info;
  334.  
  335.          assert( file != NULL );
  336.  
  337.          if (create_window( &temp, win->cline+1, win->bottom_line,
  338.                             win->start_col, win->end_col, file ) == ERROR) {
  339.             /*
  340.              * out of memory
  341.              */
  342.             error( WARNING, win->bottom_line, main4 );
  343.             rc = ERROR;
  344.          }
  345.          if (rc == OK  &&  temp != NULL) {
  346.             entab_linebuff( );
  347.             un_copy_line( win->ll, win, TRUE );
  348.             wp = temp;
  349.             /*
  350.              * record that the current window has lost some lines from
  351.              *  the bottom for the new window, and adjust its page size
  352.              *  etc accordingly.
  353.              */
  354.             win->bottom_line = win->cline;
  355.             setup_window( win );
  356.             display_current_window( win );
  357.  
  358.             /*
  359.              * set up the new cursor position as appropriate
  360.              */
  361.             wp->rcol = win->rcol;
  362.             wp->ccol = win->ccol;
  363.             wp->bcol = win->bcol;
  364.             wp->rline = win->rline;
  365.             wp->bin_offset = win->bin_offset;
  366.             wp->ll    = win->ll;
  367.             wp->cline = wp->cline + win->cline - (win->top_line + win->ruler);
  368.             if (wp->cline > wp->bottom_line)
  369.                wp->cline = wp->bottom_line;
  370.             wp->visible = TRUE;
  371.             wp->vertical = win->vertical;
  372.             wp->letter = file->next_letter++;
  373.             wp->ruler  = mode.ruler;
  374.  
  375.             /*
  376.              * the new window becomes the current window.
  377.              */
  378.             g_status.current_window = wp;
  379.  
  380.             show_window_count( g_status.window_count );
  381.             show_window_header( wp );
  382.             display_current_window( wp );
  383.             if (wp->vertical)
  384.                show_vertical_separator( wp );
  385.             make_ruler( wp );
  386.             show_ruler( wp );
  387.             rc = OK;
  388.          }
  389.       }
  390.    } else
  391.       rc = ERROR;
  392.    return( rc );
  393. }
  394.  
  395.  
  396. /*
  397.  * Name:    split_vertical
  398.  * Purpose: To split screen vertically at the cursor.
  399.  * Date:    June 5, 1991
  400.  * Passed:  window:  pointer to current window
  401.  * Notes:   split the screen vertically at the cursor position.
  402.  */
  403. int  split_vertical( WINDOW *window )
  404. {
  405. register WINDOW *wp;
  406. register WINDOW *win;   /* register pointer for window */
  407. WINDOW *temp;
  408. file_infos *file;       /* file structure for file belonging to new window */
  409. int  rc;
  410.  
  411.    rc = OK;
  412.    win = window;
  413.    if (win != NULL) {
  414.  
  415.       /*
  416.        * check that there is room for the window
  417.        */
  418.       if (win->start_col + 15 > win->ccol) {
  419.          /*
  420.           * move cursor right first
  421.           */
  422.          error( WARNING, win->bottom_line, win2 );
  423.          rc = ERROR;
  424.       } else if (win->end_col - 15 < win->ccol) {
  425.          /*
  426.           * move cursor left first
  427.           */
  428.          error( WARNING, win->bottom_line, win3 );
  429.          rc = ERROR;
  430.       } else {
  431.          file = win->file_info;
  432.  
  433.          assert( file != NULL );
  434.  
  435.          if (create_window( &temp, win->top_line-1, win->bottom_line,
  436.                             win->ccol+1, win->end_col, file ) == ERROR) {
  437.             /*
  438.              * out of memory
  439.              */
  440.             error( WARNING, win->bottom_line, main4 );
  441.             rc = ERROR;
  442.          }
  443.  
  444.          if (rc == OK  &&  temp != NULL) {
  445.             entab_linebuff( );
  446.             un_copy_line( win->ll, win, TRUE );
  447.             wp = temp;
  448.  
  449.             /*
  450.              * record that the current window has lost some columns from
  451.              *  the window to the left for the new window
  452.              */
  453.             win->ccol = win->end_col = win->ccol - 1;
  454.             win->rcol--;
  455.             win->vertical = TRUE;
  456.             show_window_header( win );
  457.             show_vertical_separator( win );
  458.             display_current_window( win );
  459.             make_ruler( win );
  460.             show_ruler( win );
  461.             show_ruler_pointer( win );
  462.  
  463.             /*
  464.              * set up the new cursor position as appropriate
  465.              */
  466.             wp->rcol = win->rcol;
  467.             wp->ccol = wp->start_col + win->ccol - win->start_col;
  468.             if (wp->ccol > wp->end_col)
  469.                wp->ccol = wp->end_col;
  470.             wp->bcol  = win->bcol;
  471.             wp->rline = win->rline;
  472.             wp->bin_offset = win->bin_offset;
  473.             wp->ll       = win->ll;
  474.             wp->cline    = win->cline;
  475.             wp->visible  = TRUE;
  476.             wp->vertical = TRUE;
  477.             wp->letter   = file->next_letter++;
  478.             wp->ruler    = mode.ruler;
  479.  
  480.             /*
  481.              * the new window becomes the current window.
  482.              */
  483.             g_status.current_window = wp;
  484.  
  485.             check_virtual_col( wp, wp->rcol, wp->ccol );
  486.             wp->file_info->dirty = FALSE;
  487.             show_window_count( g_status.window_count );
  488.             show_window_header( wp );
  489.             display_current_window( wp );
  490.             make_ruler( wp );
  491.             show_ruler( wp );
  492.          }
  493.       }
  494.    } else
  495.       rc = ERROR;
  496.    return( rc );
  497. }
  498.  
  499.  
  500. /*
  501.  * Name:    show_vertical_separator
  502.  * Purpose: To separate vertical screens
  503.  * Date:    June 5, 1991
  504.  * Passed:  window:  pointer to current window
  505.  */
  506. void show_vertical_separator( WINDOW *window )
  507. {
  508. int  i;
  509. int  line;
  510. int  col;
  511.  
  512.    line = window->top_line - 1;
  513.    col  = window->end_col + 1;
  514.    if (col < g_display.ncols - 1) {
  515.       i = window->bottom_line - line;
  516.  
  517.       assert( i <= g_display.nlines );
  518.  
  519.       while (i-- >= 0)
  520.          c_output( VERTICAL_CHAR, col, line++, g_display.head_color );
  521.    }
  522. }
  523.  
  524.  
  525. /*
  526.  * Name:    size_window
  527.  * Purpose: To change the size of the current and one other window.
  528.  * Date:    June 5, 1991
  529.  * Passed:  window:  pointer to current window
  530.  * Notes:   Use the Up and Down arrow keys to make the current window
  531.  *           bigger or smaller.  The window above will either grow
  532.  *           or contract accordingly.
  533.  */
  534. int  size_window( WINDOW *window )
  535. {
  536. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  537. int  func;
  538. int  c;
  539. int  resize;
  540. int  show_above_ruler;
  541. int  old_bottom_line;
  542. int  old_top_line;
  543. int  new_bottom_line;
  544. int  new_top_line;
  545. register WINDOW *above;
  546. register WINDOW *win;
  547.  
  548.    win = window;
  549.    if (win->top_line != 1 && !win->vertical) {
  550.       entab_linebuff( );
  551.       un_copy_line( win->ll, win, TRUE );
  552.       save_screen_line( 0, win->bottom_line, line_buff );
  553.  
  554.       /*
  555.        * press up or down to change window size
  556.        */
  557.       set_prompt( win4, win->bottom_line );
  558.  
  559.       /*
  560.        * resizing only affects current window and above visible window
  561.        */
  562.       above = g_status.window_list;
  563.       while (above->bottom_line + 2 != win->top_line || !above->visible)
  564.          above = above->next;
  565.       if (above->vertical)
  566.          /*
  567.           * cannot resize vertical window
  568.           */
  569.          error( WARNING, win->bottom_line, win5 );
  570.       else {
  571.          old_top_line = win->top_line;
  572.          old_bottom_line = above->bottom_line;
  573.          show_above_ruler = FALSE;
  574.          for (func=0; func != AbortCommand && func != Rturn; ) {
  575.  
  576.             /*
  577.              * If user has redined the ESC and Return keys, make them Rturn and
  578.              *  AbortCommand in this function.
  579.              */
  580.             c = getkey( );
  581.             func = getfunc( c );
  582.             if (c == RTURN || func == NextLine || func == BegNextLine)
  583.                func = Rturn;
  584.             else if (c == ESC)
  585.                func = AbortCommand;
  586.             resize = FALSE;
  587.  
  588.             /*
  589.              * if LineUp, make current window top line grow and bottom line
  590.              *  of above window shrink.  if window movement covers up current
  591.              *  line of window then we must adjust logical line and real line.
  592.              */
  593.             if (func == LineUp) {
  594.                if (above->bottom_line > above->top_line + above->ruler) {
  595.                   if (win->rline == (win->cline - (win->top_line+win->ruler-1)))
  596.                      --win->cline;
  597.                   --win->top_line;
  598.                   if (above->cline == above->bottom_line)
  599.                      --above->cline;
  600.                   --above->bottom_line;
  601.                   resize = TRUE;
  602.                   if (mode.ruler) {
  603.                      if (win->ruler == FALSE) {
  604.                         if (win->cline == win->top_line)
  605.                            ++win->cline;
  606.                         if (win->cline > win->bottom_line)
  607.                            win->cline = win->bottom_line;
  608.                         win->ruler = TRUE;
  609.                      }
  610.                   }
  611.                }
  612.  
  613.             /*
  614.              * if LineDown, make current window top line shrink and bottom line
  615.              *  of above window grow.  if window movement covers up current
  616.              *  line of window then we must adjust logical line and real line.
  617.              */
  618.             } else if (func == LineDown) {
  619.                if (win->bottom_line > win->top_line + win->ruler) {
  620.                   if (win->cline == win->top_line + win->ruler)
  621.                      ++win->cline;
  622.                   ++win->top_line;
  623.                   ++above->bottom_line;
  624.                   resize = TRUE;
  625.                   if (mode.ruler) {
  626.                      if (above->ruler == FALSE) {
  627.                         if (above->cline == above->top_line)
  628.                            ++above->cline;
  629.                         if (above->cline > above->bottom_line)
  630.                            above->cline = above->bottom_line;
  631.                         above->ruler = TRUE;
  632.                         make_ruler( above );
  633.                         show_above_ruler = TRUE;
  634.                      }
  635.                   }
  636.                }
  637.             }
  638.  
  639.             /*
  640.              * if we resize a window, then update window size and current and
  641.              *  real lines if needed.
  642.              */
  643.             if (resize == TRUE) {
  644.                setup_window( above );
  645.                display_current_window( above );
  646.                if (show_above_ruler) {
  647.                   show_ruler( above );
  648.                   show_ruler_pointer( above );
  649.                   show_above_ruler = FALSE;
  650.                }
  651.                setup_window( win );
  652.                show_window_header( win );
  653.                win->ruler = mode.ruler;
  654.                make_ruler( win );
  655.                show_ruler( win );
  656.                show_ruler_pointer( win );
  657.                display_current_window( win );
  658.                save_screen_line( 0, win->bottom_line, line_buff );
  659.  
  660.                /*
  661.                 * press up or down to change window size
  662.                 */
  663.                set_prompt( win4, win->bottom_line );
  664.             }
  665.          }
  666.          new_top_line = win->top_line;
  667.          new_bottom_line = above->bottom_line;
  668.          for (above=g_status.window_list; above != NULL; above=above->next) {
  669.             if (!above->visible) {
  670.                if (above->bottom_line == old_bottom_line) {
  671.                   above->bottom_line = new_bottom_line;
  672.                   if (above->cline < new_bottom_line)
  673.                      above->cline = new_bottom_line;
  674.                   setup_window( above );
  675.                } else if (above->top_line == old_top_line) {
  676.                   above->top_line = new_top_line;
  677.                   if (above->cline < new_top_line)
  678.                      above->cline = new_top_line;
  679.                   if ((long)(above->cline+1L - (above->top_line+above->ruler)) >
  680.                                                                 above->rline)
  681.                      above->cline = (int)above->rline + above->top_line +
  682.                                      above->ruler - 1;
  683.                   setup_window( above );
  684.                }
  685.             }
  686.          }
  687.       }
  688.       restore_screen_line( 0, win->bottom_line, line_buff );
  689.    } else {
  690.      if (win->vertical)
  691.         /*
  692.          * cannot resize vertical window
  693.          */
  694.         error( WARNING, win->bottom_line, win5 );
  695.      else
  696.         /*
  697.          * cannot resize top window
  698.          */
  699.         error( WARNING, win->bottom_line, win6 );
  700.    }
  701.    return( OK );
  702. }
  703.  
  704.  
  705. /*
  706.  * Name:    zoom_window
  707.  * Purpose: To blow-up current window.
  708.  * Date:    September 1, 1991
  709.  * Passed:  window:  pointer to current window
  710.  * Notes:   Make all windows, visible and hidden, full size.
  711.  */
  712. int  zoom_window( WINDOW *window )
  713. {
  714. register WINDOW *wp;
  715.  
  716.    if (window != NULL) {
  717.       entab_linebuff( );
  718.       un_copy_line( window->ll, window, TRUE );
  719.       for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  720.          if (wp != window && wp->visible)
  721.             wp->visible = FALSE;
  722.  
  723.          /*
  724.           * can't diff one window, reset the diff
  725.           */
  726.          diff.defined = FALSE;
  727.          if (wp->top_line != 1)
  728.             wp->cline = wp->cline - (wp->top_line+wp->ruler) + 1;
  729.          wp->top_line = 1;
  730.          wp->bottom_line = g_display.nlines;
  731.          wp->end_col   = g_display.ncols - 1;
  732.          wp->start_col = 0;
  733.          wp->vertical  = FALSE;
  734.          check_virtual_col( wp, wp->rcol, wp->ccol );
  735.          make_ruler( wp );
  736.       }
  737.       redraw_screen( window );
  738.       show_ruler( window );
  739.    }
  740.    return( OK );
  741. }
  742.  
  743.  
  744. /*
  745.  * Name:    next_hidden_window
  746.  * Purpose: To display the window that is "behind" current window.
  747.  * Date:    September 1, 1991
  748.  * Passed:  window:  pointer to current window
  749.  */
  750. int  next_hidden_window( WINDOW *window )
  751. {
  752. int  poof = FALSE;
  753. register WINDOW *wp;
  754.  
  755.    if (window != NULL) {
  756.  
  757.       /*
  758.        * look for next hidden window starting with current window.
  759.        */
  760.       wp = window;
  761.       for (wp=window->next; wp != NULL && !poof; ) {
  762.          if (!wp->visible)
  763.             poof = TRUE;
  764.          else
  765.             wp = wp->next;
  766.       }
  767.  
  768.       /*
  769.        * if we haven't found an invisible window yet, start looking
  770.        *  for a hidden window from the beginning of the window list.
  771.        */
  772.       if (!poof) {
  773.          for (wp=g_status.window_list; wp != NULL && !poof; ) {
  774.             if (!wp->visible)
  775.                poof = TRUE;
  776.             else
  777.                wp = wp->next;
  778.          }
  779.       }
  780.  
  781.       if (poof) {
  782.          entab_linebuff( );
  783.          un_copy_line( window->ll, window, TRUE );
  784.          wp->cline = window->top_line + window->ruler +
  785.                        (wp->cline - (wp->top_line + wp->ruler));
  786.          wp->top_line = window->top_line;
  787.          wp->bottom_line = window->bottom_line;
  788.          wp->start_col = window->start_col;
  789.          wp->end_col   = window->end_col;
  790.          wp->vertical  = window->vertical;
  791.          if (wp->cline < wp->top_line + wp->ruler)
  792.             wp->cline = wp->top_line + wp->ruler;
  793.          if (wp->cline > wp->bottom_line)
  794.             wp->cline = wp->bottom_line;
  795.          if ((wp->cline+1L - (wp->top_line+wp->ruler)) > wp->rline)
  796.             wp->cline = (int)wp->rline + wp->top_line + wp->ruler - 1;
  797.          check_virtual_col( wp, wp->rcol, wp->ccol );
  798.          wp->visible = TRUE;
  799.          window->visible = FALSE;
  800.          if (diff.defined  &&  (diff.w1 == window  ||  diff.w2 == window))
  801.             diff.defined = FALSE;
  802.          g_status.current_window = wp;
  803.          redraw_current_window( wp );
  804.          make_ruler( wp );
  805.          show_ruler( wp );
  806.       }
  807.    }
  808.    return( OK );
  809. }
  810.  
  811.  
  812. /*
  813.  * Name:    setup_window
  814.  * Purpose: To set the page length and the center line of a window, based
  815.  *           on the top and bottom lines.
  816.  * Date:    June 5, 1991
  817.  * Passed:  window: window to be set up
  818.  */
  819. void setup_window( WINDOW *window )
  820. {
  821.    window->page = window->bottom_line - (window->top_line + window->ruler) -
  822.                   g_status.overlap + 1;
  823.    if (window->page < 1)
  824.       window->page = 1;
  825. }
  826.  
  827.  
  828. /*
  829.  * Name:    finish
  830.  * Purpose: To remove the current window and terminate the program if no
  831.  *           more windows are left.
  832.  * Date:    June 5, 1991
  833.  * Passed:  window:  pointer to current window
  834.  * Notes:   Order of deciding which window becomes current window:
  835.  *          1) If any invisible window with same top and bottom line,
  836.  *          and start_col and end_col, then first invisible one becomes
  837.  *          current window.
  838.  *          2) window above if it exists becomes current window
  839.  *          3) window below if it exists becomes current window
  840.  *          4) window right if it exists becomes current window
  841.  *          5) window left  if it exists becomes current window
  842.  *          6) first available invisible window becomes current window.
  843.  *          When I added vertical windows, this routine became a LOT
  844.  *           more complicated.  To keep things reasonably sane, let's
  845.  *           only close windows that have three common edges, eg.
  846.  *
  847.  *                    ┌──────┬──────────┐
  848.  *                    │      │    no    │
  849.  *                    │      ├─────┬────┤
  850.  *                    │      │yes1 │yes1│
  851.  *                    │  no  ├─────┴────┤
  852.  *                    │      │   yes2   │
  853.  *                    │      ├──────────┤
  854.  *                    │      │   yes2   │
  855.  *                    └──────┴──────────┘
  856.  *
  857.  *          Windows with 'no' cannot be closed.  Windows with 'yes' can
  858.  *          be combined with windows that have the same yes number.
  859.  */
  860. void finish( WINDOW *window )
  861. {
  862. register WINDOW *wp;   /* for scanning other windows */
  863. register WINDOW *win;  /* register pointer for window */
  864. file_infos *file, *fp;  /* for scanning other files */
  865. int  poof;
  866. int  cline;
  867. int  top;
  868. int  bottom;
  869. int  start_col;
  870. int  end_col;
  871. int  max_letter;
  872. int  file_change = FALSE;
  873. line_list_ptr ll;
  874. line_list_ptr temp_ll;
  875.  
  876.    win = window;
  877.    entab_linebuff( );
  878.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  879.       return;
  880.  
  881.    file = win->file_info;
  882.    /*
  883.     * remove all hidden windows that point to same file
  884.     */
  885.    file = win->file_info;
  886.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  887.       if (wp->file_info == file) {
  888.          if (!wp->visible) {
  889.             if (wp->prev == NULL) {
  890.                if (wp->next == NULL)
  891.                   g_status.stop = TRUE;
  892.                else
  893.                   g_status.window_list = wp->next;
  894.             } else
  895.                wp->prev->next = wp->next;
  896.             if (wp->next)
  897.                wp->next->prev = wp->prev;
  898.             --wp->file_info->ref_count;
  899.             free( wp );
  900.             --g_status.window_count;
  901.          }
  902.       }
  903.    }
  904.  
  905.    if (win->prev == NULL && win->next == NULL)
  906.       g_status.stop = TRUE;
  907.  
  908.    poof = FALSE;
  909.  
  910.    if (g_status.stop != TRUE) {
  911.       /*
  912.        * see if there are any invisible windows with same top and bottom,
  913.        *  lines, and start_col and end_col as this window.  start looking at
  914.        *  end of window list.
  915.        */
  916.       top       = win->top_line;
  917.       bottom    = win->bottom_line;
  918.       start_col = win->start_col;
  919.       end_col   = win->end_col;
  920.       wp = g_status.window_list;
  921.       if (wp != NULL) {
  922.          while (wp->next != NULL)
  923.             wp = wp->next;
  924.       }
  925.       while (wp != NULL && poof == FALSE) {
  926.          if (wp->top_line == top         &&  wp->bottom_line == bottom  &&
  927.              wp->start_col == start_col  &&  wp->end_col == end_col     &&
  928.                                                               !wp->visible)
  929.             poof = TRUE;
  930.          else
  931.             wp = wp->prev;
  932.       }
  933.  
  934.       if (poof == FALSE) {
  935.          /*
  936.           * see if there are any windows above
  937.           */
  938.          wp = g_status.window_list;
  939.          while (wp != NULL && poof == FALSE) {
  940.             if (wp->bottom_line+2 == win->top_line &&
  941.                 wp->start_col     == win->start_col &&
  942.                      wp->end_col       == win->end_col   && wp->visible) {
  943.                poof = TRUE;
  944.                top  = wp->top_line;
  945.             } else
  946.                wp = wp->next;
  947.          }
  948.          if (poof == FALSE) {
  949.             /*
  950.              * see if there are any windows below
  951.              */
  952.             wp = g_status.window_list;
  953.             while (wp != NULL && poof == FALSE) {
  954.                if (wp->top_line-2 == win->bottom_line  &&
  955.                    wp->start_col     == win->start_col &&
  956.                          wp->end_col    == win->end_col   && wp->visible) {
  957.                   poof = TRUE;
  958.                   bottom = wp->bottom_line;
  959.                } else
  960.                   wp = wp->next;
  961.             }
  962.          }
  963.          if (poof == FALSE) {
  964.             /*
  965.              * see if there are any windows right
  966.              */
  967.             wp = g_status.window_list;
  968.             while (wp != NULL && poof == FALSE) {
  969.                if (wp->top_line    == win->top_line  &&
  970.                          wp->bottom_line == win->bottom_line &&
  971.                          wp->start_col-2 == win->end_col     && wp->visible) {
  972.                   poof = TRUE;
  973.                   end_col = wp->end_col;
  974.                } else
  975.                   wp = wp->next;
  976.             }
  977.          }
  978.          if (poof == FALSE) {
  979.             /*
  980.              * see if there are any windows left
  981.              */
  982.             wp = g_status.window_list;
  983.             while (wp != NULL && poof == FALSE) {
  984.                if (wp->top_line    == win->top_line  &&
  985.                    wp->bottom_line == win->bottom_line &&
  986.                    wp->end_col+2   == win->start_col   && wp->visible) {
  987.                   poof = TRUE;
  988.                   start_col = wp->start_col;
  989.                } else
  990.                   wp = wp->next;
  991.             }
  992.          }
  993.          if (poof == FALSE) {
  994.             /*
  995.              * see if there are any other invisible windows.  start looking
  996.              *  at the end of the window list.
  997.              */
  998.             wp = g_status.window_list;
  999.             if (wp != NULL) {
  1000.                while (wp->next != NULL)
  1001.                   wp = wp->next;
  1002.             }
  1003.             while (wp != NULL && poof == FALSE) {
  1004.                if (!wp->visible)
  1005.                   poof = TRUE;
  1006.                else
  1007.                   wp = wp->prev;
  1008.             }
  1009.          }
  1010.       }
  1011.       if (poof) {
  1012.          wp->visible = TRUE;
  1013.          cline = wp->cline - (wp->top_line+wp->ruler);
  1014.          wp->top_line = top;
  1015.          wp->bottom_line = bottom;
  1016.          wp->cline = (wp->top_line+wp->ruler) + cline;
  1017.          if (wp->cline > wp->bottom_line)
  1018.             wp->cline = wp->top_line+wp->ruler;
  1019.          wp->start_col = start_col;
  1020.          wp->end_col   = end_col;
  1021.          if (start_col == 0 && end_col == g_display.ncols - 1)
  1022.             wp->vertical = FALSE;
  1023.          else
  1024.             wp->vertical = TRUE;
  1025.          check_virtual_col( wp, wp->rcol, wp->ccol );
  1026.          setup_window( wp );
  1027.          show_window_header( wp );
  1028.          if (wp->vertical)
  1029.             show_vertical_separator( wp );
  1030.  
  1031.          /*
  1032.           * The window above, below, or previously invisible becomes the new
  1033.           *  current window.
  1034.           */
  1035.          g_status.current_window = wp;
  1036.       }
  1037.    }
  1038.  
  1039.    if (!poof && g_status.stop != TRUE)
  1040.       /*
  1041.        * cannot close current window
  1042.        */
  1043.       error( WARNING, win->bottom_line, win7 );
  1044.    else {
  1045.  
  1046.       /*
  1047.        * free unused file memory if necessary
  1048.        */
  1049.       if (--file->ref_count == 0) {
  1050.  
  1051.          /*
  1052.           * if a block is marked, unmark it
  1053.           */
  1054.          if (file == g_status.marked_file) {
  1055.             g_status.marked      = FALSE;
  1056.             g_status.marked_file = NULL;
  1057.          }
  1058.  
  1059.          for (fp=g_status.file_list; fp != NULL; fp=fp->next) {
  1060.             if (fp->file_no > file->file_no)
  1061.                fp->file_no--;
  1062.          }
  1063.          file_change = file->file_no;
  1064.  
  1065.          /*
  1066.           * no window now refers to this file, so remove file from the list
  1067.           */
  1068.          if (file->prev == NULL)
  1069.             g_status.file_list = file->next;
  1070.          else
  1071.             file->prev->next = file->next;
  1072.          if (file->next)
  1073.             file->next->prev = file->prev;
  1074.  
  1075.          /*
  1076.           * free the line pointers, linked list of line pointers, and
  1077.           *  file struc.
  1078.           */
  1079.          ll = file->undo_top;
  1080.          while (ll != NULL) {
  1081.             temp_ll = ll->next;
  1082.             if (ll->line != NULL)
  1083.                my_free( ll->line );
  1084.             my_free( ll );
  1085.             ll = temp_ll;
  1086.          }
  1087.  
  1088.          ll = file->line_list;
  1089.          while (ll != NULL) {
  1090.             temp_ll = ll->next;
  1091.             if (ll->line != NULL)
  1092.                my_free( ll->line );
  1093.             my_free( ll );
  1094.             ll = temp_ll;
  1095.          }
  1096.  
  1097. #if defined( __MSC__ )
  1098.          _fheapmin( );
  1099. #endif
  1100.  
  1101.          free( file );
  1102.          if (--g_status.file_count) {
  1103.             show_file_count( g_status.file_count );
  1104.             show_avail_mem( );
  1105.          }
  1106.       }
  1107.  
  1108.       /*
  1109.        * remove the current window from the window list
  1110.        */
  1111.       if (win->prev == NULL)
  1112.          g_status.window_list = win->next;
  1113.       else
  1114.          win->prev->next = win->next;
  1115.  
  1116.       if (win->next)
  1117.          win->next->prev = win->prev;
  1118.  
  1119.       if (diff.defined  &&  (diff.w1 == win  ||  diff.w2 == win))
  1120.          diff.defined = FALSE;
  1121.  
  1122.       /*
  1123.        * free the memory taken by the window structure
  1124.        */
  1125.       free( win );
  1126.       --g_status.window_count;
  1127.  
  1128.       if (g_status.stop == FALSE) {
  1129.          g_status.current_file = wp->file_info;
  1130.          wp->file_info->dirty = LOCAL;
  1131.          make_ruler( wp );
  1132.          show_ruler( wp );
  1133.          show_window_count( g_status.window_count );
  1134.          if (file_change) {
  1135.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next)
  1136.                if (wp->visible)
  1137.                   show_window_number_letter( wp );
  1138.          } else {
  1139.             max_letter = 'a';
  1140.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  1141.                if (wp->file_info == file && wp->letter > max_letter)
  1142.                   max_letter = wp->letter;
  1143.             }
  1144.             if (max_letter < file->next_letter - 1)
  1145.                file->next_letter = max_letter + 1;
  1146.          }
  1147.       }
  1148.    }
  1149.  
  1150.    if (g_status.stop == TRUE) {
  1151.       if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1152.          show_avail_mem( );
  1153.          for (bottom=0; bottom <= g_display.nlines; bottom++)
  1154.             eol_clear( 0, bottom, g_display.text_color );
  1155.          bottom  = g_display.nlines;
  1156.          set_prompt( win18, bottom );
  1157.          top = getkey( );
  1158.          top = getfunc( top );
  1159.          eol_clear( 0, bottom, g_display.text_color );
  1160.          if (top == RepeatGrep) {
  1161.             g_status.command = RepeatGrep;
  1162.             g_status.window_list = g_status.current_window = NULL;
  1163.             if (search_and_seize( g_status.window_list ) != ERROR)
  1164.                g_status.stop = FALSE;
  1165.          }
  1166.       }
  1167.    }
  1168. }
  1169.  
  1170.  
  1171. /*
  1172.  * Name:    create_window
  1173.  * Purpose: To allocate space for a new window structure and set up some
  1174.  *           of the relevant fields.
  1175.  * Date:    June 5, 1991
  1176.  * Passed:  window: pointer to window pointer
  1177.  *          top:    the top line of the new window
  1178.  *          bottom: the bottom line of the new window
  1179.  *          start_col:  starting column of window on screen
  1180.  *          end_col:    ending column of window on screen
  1181.  *          file:   the file structure to be associated with the new window
  1182.  * Returns: OK if window could be created
  1183.  *          ERROR if out of memory
  1184.  */
  1185. int  create_window( WINDOW **window, int top, int bottom, int start_col,
  1186.                     int end_col, file_infos *file )
  1187. {
  1188. WINDOW *wp;             /* temporary variable - use it instead of **window */
  1189. register WINDOW *prev;
  1190. int  rc;                /* return code */
  1191.  
  1192.    rc = OK;
  1193.    /*
  1194.     * allocate space for new window structure
  1195.     */
  1196.    if ((*window = (WINDOW *)calloc( 1, sizeof(WINDOW) )) == NULL) {
  1197.       /*
  1198.        * out of memory
  1199.        */
  1200.       error( WARNING, g_display.nlines, main4 );
  1201.       rc = ERROR;
  1202.    } else {
  1203.  
  1204.      /*
  1205.       * set up appropriate fields
  1206.       */
  1207.       wp              = *window;
  1208.       wp->file_info   = file;
  1209.       wp->top_line    = top+1;
  1210.       wp->bottom_line = bottom;
  1211.       wp->start_col   = start_col;
  1212.       wp->end_col     = end_col;
  1213.       wp->bin_offset  = 0;
  1214.       wp->ruler       = mode.ruler;
  1215.       make_ruler( wp );
  1216.       wp->cline       = wp->top_line + wp->ruler;
  1217.       if (start_col == 0 && end_col == g_display.ncols-1)
  1218.          wp->vertical = FALSE;
  1219.       else
  1220.          wp->vertical = TRUE;
  1221.       wp->prev        = NULL;
  1222.       wp->next        = NULL;
  1223.  
  1224.       setup_window( wp );
  1225.  
  1226.       /*
  1227.        * add window into window list
  1228.        */
  1229.       prev = g_status.current_window;
  1230.       if (prev) {
  1231.          (*window)->prev = prev;
  1232.          if (prev->next)
  1233.             prev->next->prev = *window;
  1234.          (*window)->next = prev->next;
  1235.          prev->next = *window;
  1236.       }
  1237.       if (g_status.window_list == NULL)
  1238.          g_status.window_list = *window;
  1239.  
  1240.       /*
  1241.        * record that another window is referencing this file
  1242.        */
  1243.       ++file->ref_count;
  1244.       file->dirty = LOCAL;
  1245.       ++g_status.window_count;
  1246.    }
  1247.    return( rc );
  1248. }
  1249.